package com.smap.vector;

import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;

import com.smap.core.Map;
import com.smap.core.Projection;
import com.smap.core.XY;

public class Feature {

	// 0 = normal, 1 = creating, 2 = modifying
	public int status = 0;

	public LinkedHashMap<String, String> properties = new LinkedHashMap<String, String>();
	public Geometry geom;
	public Style style = new Style();

	@SuppressWarnings("serial")
	LinkedHashMap<String, Geometry> cache = new LinkedHashMap<String, Geometry>() {
		protected boolean removeEldestEntry(
				java.util.Map.Entry<String, Geometry> eldest) {
			return size() > 10;
		};
	};

	public Geometry screenGeom;

	public Feature() {
	}

	public Feature(Geometry geom, Style style) {
		this.geom = geom;
		if (style != null) {
			this.style = style;
		}
	}

	public void label(String label) {
		this.properties.put("label", label);
	}

	public Geometry createScreen(Map map) {
		return createScreen(map, false);
	}

	public Geometry createScreen(Map map, boolean force) {
		XY centroid = map.getCentre();
		double res = map.getResolution();
		String key = centroid + "-" + res;
		screenGeom = cache.get(key);
		if (screenGeom == null || force) {
			screenGeom = GeomUtils.clone(this.geom);
			for (XY pt : screenGeom.coordinates) {
				pt.x = ((pt.x - centroid.x) / res);
				pt.y = -((pt.y - centroid.y) / res);
			}
			if (status == 0) {
				simplify(screenGeom, 5);
			}
			cache.put(key, screenGeom.pack());
		}
		return screenGeom;
	}

	private void simplify(Geometry geom, int tolerance) {
		List<XY> pts = geom.coordinates;
		List<XY> simpled = new ArrayList<XY>();
		XY last = null;
		for (int i = 0; i < pts.size(); i++) {
			XY xy = pts.get(i);
			xy.x = (int) xy.x;
			xy.y = (int) xy.y;
			if ((i == 0) || (i == pts.size() - 1)) {
				if ((i > 0) && (pts.get(i - 1) != last)) {
					simpled.add(pts.get(i - 1));
				}
				simpled.add(last = xy);
			} else if (xy.distance(last) > tolerance) {
				simpled.add(last = pts.get(i - 1));
			}
		}
		// System.out.println(geom.coordinates.size());
		geom.coordinates.clear();
		geom.coordinates.addAll(simpled);
		// System.out.println(geom.coordinates.size());
	}

	public void project(Projection proj) {
		for (XY xy : this.geom.coordinates) {
			proj.project(xy);
		}
		this.geom.pack();
	}

	public void reversePack(Map map) {
		XY centroid = map.getCentre();
		double res = map.getResolution();
		geom = GeomUtils.clone(this.screenGeom);
		for (XY p : geom.coordinates) {
			p.x = centroid.x + p.x * res;
			p.y = centroid.y - p.y * res;
		}
	}

	public void screenToCoord(Map map, XY p) {
		XY centroid = map.getCentre();
		double res = map.getResolution();
		geom = GeomUtils.clone(this.screenGeom);
		p.x = centroid.x + p.x * res;
		p.y = centroid.y - p.y * res;
	}

}
